package com.google.projectulator;

import java.io.CharArrayWriter;
import java.io.File;
import java.io.PrintWriter;

import org.apache.commons.io.FileUtils;
import org.apache.maven.plugin.MojoExecutionException;

import com.google.projectulator.exception.ProjectulatorException;

/**
 * Provides default error handling, which is to...
 * @author Lance Woodson
 *
 */
public class DefaultErrorHandler extends BaseProjectulatorDelegate implements ErrorHandler {
	public static final String LOCATION_PARAM = "errorHandler.fileLocation";
	public static final String DEFAULT_LOCATION = "projectulator.error";
	private String location;
	
	public DefaultErrorHandler() {
		name = "DefaultErrorHandler";
	}
	
	public void init(Config config) {
		location = config.getOrDefault(LOCATION_PARAM, DEFAULT_LOCATION);
	}
	
	public void handle(Context context, Exception exception) throws MojoExecutionException {
		log.debug("ExceptionHandler handling " + exception.getClass().getName());
		try {
			StringBuilder builder = new StringBuilder("[ERROR]\n");
			appendDelegateInfo(builder, context.getProjectCollector(), context.getProjectCollector().getCollector().getName(), "PROJECT COLLECTOR: ");
			builder.append("\n");
			appendDelegateInfo(builder, context.getPreProcessorState(), context.getPreProcessorState().getProcessor().getName(), "PRE-PROCESSOR: ");
			builder.append("\n");
			if (context.getProjects() != null) {
				for (ProjectState projectState : context.getProjects()) {
					appendDelegateInfo(builder, projectState, projectState.getName(), "  PROJECT: ");
					if (projectState.getProcessorStates() != null) {
						for (ProcessorState processorState : projectState.getProcessorStates()) {
							appendDelegateInfo(builder, processorState, processorState.getProcessor().getName(), "    PROCESSOR: ");
						}
					}
				}
			}
			builder.append("\n");
			appendDelegateInfo(builder, context.getPostProcessorState(), context.getPostProcessorState().getProcessor().getName(), "POST-PROCESSOR: ");
			
			appendStackTrace(exception, builder);
			
			File f = new File(location);
			FileUtils.writeStringToFile(f, builder.toString());
			log.error(builder.toString());
		} catch (Exception e) {
			log.warn("Unable to handle " + e, e);
		} finally {
			throw new MojoExecutionException("error", exception);
		}
	}

	void appendStackTrace(Exception exception,
			StringBuilder builder) {
		builder.append("\n\n[Stack Trace]\n");
		CharArrayWriter writer = new CharArrayWriter();
		PrintWriter printWriter = new PrintWriter(writer);
		exception.printStackTrace(printWriter);
		builder.append(writer.toString());
	}
	
	void appendDelegateInfo(StringBuilder builder, ProcessingState state, String name, String prepend) {
		builder.append(prepend).append(name).append(": ").append(state.getStatus());
		if (state.getStatus() == Status.ERROR) {
			builder.append(" - ").append(state.getErrorString());
		}
		builder.append("\n");
	}
	
	public String getLocation() {
		return location;
	}
	
	public void setLocation(String location) {
		this.location = location;
	}
	
	@Override
	public String toString() {
		return "DefaultErrorHandler(" + name + ")";
	}
}
